1. Introduction to Data Preparation

Data preparation is the very first thing that you do and spend a lot of time on as a data analyst much before trying to build predictive models using that data.

In essence data preparation is all about processing data to get it ready for all kinds of analysis. In industry data collection is mostly driven by business process at front, not by the needs of predictive models. These various processes at some or the other point become reason for introduction of errors here and there in the data.


2. Data Processing

There can be many kind of reasons not necessarily errors for which we would need to pre-process our data and change it for better.

2.1 Load Libraries and Packages

Lets begin with importing all the relevant libraries and packages.

library(dplyr)
library(psych)
library(vcd)

2.2 Importing Data

We are going to import data file bank-full.csv here. Lets begin, we’ll start with passing just the file name and let all other be option take their defaults. We’ll change some as we come across issue with the imported data.

bd = read.csv("https://raw.githubusercontent.com/insaid2018/R/master/Data/bank-full.csv")
head(bd,2)

2.3 Reading Data

You can see that we have been fooled by the file extension and assumed that the separator for the data is comma where as in reality it is “;”. Lets tell that to R by using option sep.

bd = read.csv("https://raw.githubusercontent.com/insaid2018/R/master/Data/bank-full.csv", sep=";")
head(bd,2)

Okay, this looks better. Now, lets look at our data.

glimpse(bd)
Observations: 45,211
Variables: 17
$ age       <int> 58, 44, 33, 47, 33, 35, 28, 42, 58, 43, 41, 29, 53, 58, 57, 51, 45, 57, 60, ...
$ job       <fct> management, technician, entrepreneur, blue-collar, unknown, management, mana...
$ marital   <fct> married, single, married, married, single, married, single, divorced, marrie...
$ education <fct> tertiary, secondary, secondary, unknown, unknown, tertiary, tertiary, tertia...
$ default   <fct> no, no, no, no, no, no, no, yes, no, no, no, no, no, no, no, no, no, no, no,...
$ balance   <int> 2143, 29, 2, 1506, 1, 231, 447, 2, 121, 593, 270, 390, 6, 71, 162, 229, 13, ...
$ housing   <fct> yes, yes, yes, yes, no, yes, yes, yes, yes, yes, yes, yes, yes, yes, yes, ye...
$ loan      <fct> no, no, yes, no, no, no, yes, no, no, no, no, no, no, no, no, no, no, no, no...
$ contact   <fct> unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unkn...
$ day       <int> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...
$ month     <fct> may, may, may, may, may, may, may, may, may, may, may, may, may, may, may, m...
$ duration  <int> 261, 151, 76, 92, 198, 139, 217, 380, 50, 55, 222, 137, 517, 71, 174, 353, 9...
$ campaign  <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1...
$ pdays     <int> -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ...
$ previous  <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
$ poutcome  <fct> unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unkn...
$ y         <fct> no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, ...

We can also compute the descriptive statistics using the describe function available in psych package.

describe(bd)

Lets look at the 6 point summary of our data using the summary function.

summary(bd)
      age                 job           marital          education     default    
 Min.   :18.00   blue-collar:9732   divorced: 5207   primary  : 6851   no :44396  
 1st Qu.:33.00   management :9458   married :27214   secondary:23202   yes:  815  
 Median :39.00   technician :7597   single  :12790   tertiary :13301              
 Mean   :40.94   admin.     :5171                    unknown  : 1857              
 3rd Qu.:48.00   services   :4154                                                 
 Max.   :95.00   retired    :2264                                                 
                 (Other)    :6835                                                 
    balance       housing      loan            contact           day            month      
 Min.   : -8019   no :20081   no :37967   cellular :29285   Min.   : 1.00   may    :13766  
 1st Qu.:    72   yes:25130   yes: 7244   telephone: 2906   1st Qu.: 8.00   jul    : 6895  
 Median :   448                           unknown  :13020   Median :16.00   aug    : 6247  
 Mean   :  1362                                             Mean   :15.81   jun    : 5341  
 3rd Qu.:  1428                                             3rd Qu.:21.00   nov    : 3970  
 Max.   :102127                                             Max.   :31.00   apr    : 2932  
                                                                            (Other): 6060  
    duration         campaign          pdays          previous           poutcome       y        
 Min.   :   0.0   Min.   : 1.000   Min.   : -1.0   Min.   :  0.0000   failure: 4901   no :39922  
 1st Qu.: 103.0   1st Qu.: 1.000   1st Qu.: -1.0   1st Qu.:  0.0000   other  : 1840   yes: 5289  
 Median : 180.0   Median : 2.000   Median : -1.0   Median :  0.0000   success: 1511              
 Mean   : 258.2   Mean   : 2.764   Mean   : 40.2   Mean   :  0.5803   unknown:36959              
 3rd Qu.: 319.0   3rd Qu.: 3.000   3rd Qu.: -1.0   3rd Qu.:  0.0000                              
 Max.   :4918.0   Max.   :63.000   Max.   :871.0   Max.   :275.0000                              
                                                                                                 

2.4 Changing Data Types

You can see that all of our character columns have been stored as factors. This needs to be avoided. And we can do so by using option stringsAsFactors.

bd=read.csv("https://raw.githubusercontent.com/insaid2018/R/master/Data/bank-full.csv", sep=";",stringsAsFactors = FALSE)
glimpse(bd)
Observations: 45,211
Variables: 17
$ age       <int> 58, 44, 33, 47, 33, 35, 28, 42, 58, 43, 41, 29, 53, 58, 57, 51, 45, 57, 60, ...
$ job       <chr> "management", "technician", "entrepreneur", "blue-collar", "unknown", "manag...
$ marital   <chr> "married", "single", "married", "married", "single", "married", "single", "d...
$ education <chr> "tertiary", "secondary", "secondary", "unknown", "unknown", "tertiary", "ter...
$ default   <chr> "no", "no", "no", "no", "no", "no", "no", "yes", "no", "no", "no", "no", "no...
$ balance   <int> 2143, 29, 2, 1506, 1, 231, 447, 2, 121, 593, 270, 390, 6, 71, 162, 229, 13, ...
$ housing   <chr> "yes", "yes", "yes", "yes", "no", "yes", "yes", "yes", "yes", "yes", "yes", ...
$ loan      <chr> "no", "no", "yes", "no", "no", "no", "yes", "no", "no", "no", "no", "no", "n...
$ contact   <chr> "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",...
$ day       <int> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...
$ month     <chr> "may", "may", "may", "may", "may", "may", "may", "may", "may", "may", "may",...
$ duration  <int> 261, 151, 76, 92, 198, 139, 217, 380, 50, 55, 222, 137, 517, 71, 174, 353, 9...
$ campaign  <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1...
$ pdays     <int> -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ...
$ previous  <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
$ poutcome  <chr> "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",...
$ y         <chr> "no", "no", "no", "no", "no", "no", "no", "no", "no", "no", "no", "no", "no"...

2.5 Handling Missing Data

Next, lets look at what values our variable job takes.

table(bd$job)

       admin.   blue-collar  entrepreneur     housemaid    management       retired self-employed 
         5171          9732          1487          1240          9458          2264          1579 
     services       student    technician    unemployed       unknown 
         4154           938          7597          1303           288 

There are 288 observations where the value is unknown, if you want, you can set it to missing by using option na.strings. But, remember this will set the value unknown as missing for all the columns. If you want to do it only for one of columns then do that after you have imported the data.

bd=read.csv("bank-full.csv",sep=";",stringsAsFactors = FALSE,na.strings = "unknown")
sum(is.na(bd$job))

You can see that, now column job has 288 missing values. This was to show you how to use option na.string. In general it is not a good practice to set any random value as missing. So, for practice its alright, but dont set unknown to missing in general unless you have good reason to do so. In fact in many of the cases of categorical variables, unknown itself can be taken as a valid category as you’ll realise later.

We dont need to change default values of other options for this importing. Same will be the case for you as well for most of the data. If it is not, feel free to use any of the option described above.



3. Data Operations

We’ll start with discussion on apply family of functions which are very handy way to summarize as well as do other operations collectively on your data. Lets say we want to get means of all columns present in the data mtcars. We could achieve that writing a for loop across columns with function mean.

rr for(i in 1:ncol(mtcars)){ print(mean(mtcars[,i])) }

[1] 20.09062
[1] 6.1875
[1] 230.7219
[1] 146.6875
[1] 3.596563
[1] 3.21725
[1] 17.84875
[1] 0.4375
[1] 0.40625
[1] 3.6875
[1] 2.8125

Fine you get the result, but its not in a very convenient format and code is not pretty. What if there exists a function which lets us do this without writing these loops and having to go through managing iterations for a function. This is such a common scenario in data processing, R has a family of dedicated funcitons for this.

rr x=round(rnorm(10),2) x

 [1]  0.07  0.34 -1.99  1.03 -0.87  1.44  0.58 -0.23  1.25 -0.48


3.1 Apply Functions

We’ll first talk about lapply. This lets you apply a function repeatedly on a list/vector, the outcome is a list of results. Lets see an example.

rr lapply(x,log10)

NaNs producedNaNs producedNaNs producedNaNs produced
[[1]]
[1] -1.154902

[[2]]
[1] -0.4685211

[[3]]
[1] NaN

[[4]]
[1] 0.01283722

[[5]]
[1] NaN

[[6]]
[1] 0.1583625

[[7]]
[1] -0.236572

[[8]]
[1] NaN

[[9]]
[1] 0.09691001

[[10]]
[1] NaN

But above operation can be easily achieved using vector operations. Infact a simple log(x) will give you the same result and in a much usable format as well. But then what good is this lapply thing?

Lets put it to a better use and with more options. How about, if you had a lot of text files in your folder and you wanted to import them all. One solution will be to write one line of read.csv for all these files or may be you can run a loop. Better you could pass all those names to function read.csv using lapply.

rr # Before running these codes , you’ll have to set your working directory to the folder . file_names = list.files(getwd(), pattern = *.TXT) files = lapply(file_names, read.csv, header = F, stringsAsFactors = F)


See, we can pass other common options to function read.csv in lapply. File names in the object file_names are passed one by one to function read.csv. The output file is simply a list of data frames. If you want to combine them, you can do so by using function do.call.

rr file = do.call(rbind,files)

do.call here passes all the elements in the second argument to function mentioned in first argument.


In just three simple lines of code, we have read data from 50+ files and combined it into one. In just three lines! All thanks to lapply. At times the output in form of a list becomes difficult to handle.

You can use sapply in these cases. sapply works exactly like lapply, only difference being, it tries to vectorise output of lapply if it is possible.

rr sapply(x, log)

NaNs producedNaNs producedNaNs producedNaNs produced
 [1] -2.6592600 -1.0788097        NaN  0.0295588        NaN  0.3646431 -0.5447272        NaN
 [9]  0.2231436        NaN

Coming back to our first problem of getting mean for all columns. Yes, you can use lapply, because data frames are nothing but list of vectors. There is another function in apply family named apply which provides better output and a little more funcitonality when you want to apply function iteratively on data frame elements.

rr apply(mtcars,2,mean)

       mpg        cyl       disp         hp       drat         wt       qsec         vs         am 
 20.090625   6.187500 230.721875 146.687500   3.596563   3.217250  17.848750   0.437500   0.406250 
      gear       carb 
  3.687500   2.812500 

The first argument to apply is the name of the data frame. Third argument is the function which is going to get applied. Second argument takes two values: [1 or 2]. 1 stands for rows and 2 for columns. Which means, if you put 2 in the second argument, function in the third argument will be applied on the columns of the data frames. If the value is given as 1, function gets applied on rows.


Functions which you pass to apply are not limited to pre existing function in R. You can write your own and pass it to apply family functions. Lets write a function which returns upper limit of outliers given a variable column.

rr outlier_upper=function(x){ m=mean(x); s=sd(x); return(m+3*s); } apply(mtcars,2,outlier_upper)

       mpg        cyl       disp         hp       drat         wt       qsec         vs         am 
 38.171469  11.545265 602.537956 352.376105   5.200599   6.152622  23.209580   1.949548   1.903223 
      gear       carb 
  5.900912   7.658100 

What you need to remember here is what goes as input to the function. In case of apply, input is the entire row or column. Lets use apply to find out how many outliers each column has according to function oulier_upper.

rr apply(mtcars,2,function(x) sum(x>outlier_upper(x)))

 mpg  cyl disp   hp drat   wt qsec   vs   am gear carb 
   0    0    0    0    0    0    0    0    0    0    1 

What if you want to get a group wise summary of any variable. tapply comes to your rescue. First arguement to tapply is the column for which we are looking for summary, second argument is the grouping variable, third argument is the function which will be applied on the groups.

rr tapply(mtcars\(mpg,mtcars\)am,mean)

       0        1 
17.14737 24.39231 

For getting group wise summary of all the variable in the dataset mtcars you can use a combination of apply and tapply.

rr apply(mtcars,2,function(x) tapply(x,mtcars$am,mean))

       mpg      cyl     disp       hp     drat       wt     qsec        vs am     gear     carb
0 17.14737 6.947368 290.3789 160.2632 3.286316 3.768895 18.18316 0.3684211  0 3.210526 2.736842
1 24.39231 5.076923 143.5308 126.8462 4.050000 2.411000 17.36000 0.5384615  1 4.384615 2.923077


3.2 Adding Variables

Creating variables/vectors with simple algebraic operations is straight forward. Lets add one variable to data frame Arthritis.

rr library(vcd) Arthritis\(new=log(Arthritis\)Age) head(Arthritis)


What if we wanted to create an indicator variable which takes value 0 or 1 according to Age being less than or greater than 40? These simple algebraic operations will not work. We’ll have to use conditional operators.

rr Arthritis\(new=as.numeric(Arthritis\)Age<40) head(Arthritis)


This seems trivial too, now what if we want Age to be floored to 40 whenever it is less than 40 and other wise kept as it is. We wont be able to achieve this with simple conditional statement either.

rr x = sample(40,10) x

 [1] 26 18  9 11 12 40 31  2 34 14

We will be using function ifelse to achieve the same.

rr y = ifelse(x>20,20,x) y

 [1] 20 18  9 11 12 20 20  2 20 14

Now, lets use this to add a variable in the data frame.

rr Arthritis\(new = ifelse(Arthritis\)Age<40, 40, Arthritis$Age) head(Arthritis)



4. Data Wrangling

We have seen ways to modify and summarise data in base R. Again those functionalities are kind of scattered and not streamlined. If you think about it you can achieve almost all kind of modifications to data using these verbs:

Package dplyr comes with these verbs for data wrangling. Next, we’ll see how to achieve different data wrangling task in base R and the same in dplyr. Of course dplyr comes with some addtional fuctionlaities too and we’ll be looking at those as well.

Before we start, install packages dplyr and hflights.

rr library(dplyr) library(hflights)


We’ll be using data set hflights. You can get details of the data hflights after you have loaded library hflights by typing ?hflights.

rr ?hflights


Lets have a look at our data.

rr data(hflights) head(hflights)


We’ll start with our first function tbl_df which converts a data.frame to a tabular format for which display on console is better. It changes nothing else about the data frame.

rr flights = tbl_df(hflights) flights


4.1 Filter Data

Lets look at condition filtering of the data. We’ll start with base R approach to view all flights on January 1

rr flights[flights\(Month==1 & flights\)DayofMonth==1,]


4.1.1 dplyr Approach

You can use comma or ampersand to represent AND condition

rr #note: you can use comma or ampersand to represent AND condition filter(flights, Month==1, DayofMonth==1)


You can use pipe for OR condition

rr # You can use pipe for OR condition filter(flights, UniqueCarrier== | UniqueCarrier==)


You can also use %in% operator.

rr # You can also use %in% operator filter(flights, UniqueCarrier %in% c(, ))

See, you don’t need to bother with that $ reference to data frame all the time. Code is much neater and readable.


4.2 Select Data

Lets look at column selection dropping by name. You’ll be definietly surprised by the additional functionalities of dplyr.

rr # base R approach to select DepTime, ArrTime, and FlightNum columns flights[, c(, , )]

rr # dplyr approach select(flights, DepTime, ArrTime, FlightNum)


Use colon to select multiple continuous columns, and use contains to match columns by name note: “starts_with”, “ends_with” can also be used to match columns by name

rr select(flights, Year:DayofMonth, contains(), contains())


Now, what if we wanted to do many operations at once; for example, selction and conditional filtering. We can do so by nesting our functions.

rr # nesting method to select UniqueCarrier and DepDelay columns and filter for delays over 60 minutes filter(select(flights, UniqueCarrier, DepDelay), DepDelay > 60)

This nesting methodology becomes very cumbersome. This defies the purpose with which we started, making our code more readable.


Here comes to your rescue %>% operator, also called chaining operator. Basically, when you use this operator, every subsequent line of code inherits inputs from the previous line. You’ll be able to better understand this with the following example. Later on we’ll rewrite the above nested code with the chaining operator.

rr x=sample(10,6) x %>% log() %>% sum()

[1] 8.014336

See, you don’t have to pass any input to those functions, x goes as input to log and then modified x as log(x) goes as input to sum.


Lets see how we can use this to rewrite the nested function that we saw above.

rr # chaining method flights %>% select(UniqueCarrier, DepDelay) %>% filter(DepDelay > 60)

See, no need to nest or keep on giving data reference for every operation. Isn’t that neat!!



4.3 Sort Data

Next we move to ordering/sorting our data by using verb arrange.

rr # base R approach to select UniqueCarrier and DepDelay columns and sort by DepDelay flights[order(flights$DepDelay), c(, )]

rr # dplyr approach flights %>% select(UniqueCarrier, DepDelay) %>% arrange(DepDelay)



4.4 Modify Data

Next step is to mutate or modifying/adding data to existing data.

rr # base R approach to create a new variable Speed (in mph) flights\(Speed <- flights\)Distance / flights$AirTime*60 flights[, c(, , )]

rr # dplyr approach flights %>% select(Distance, AirTime) %>% mutate(Speed = Distance/AirTime*60)


What we have been doing is getting the output to display, if you wanted to save it could do as we usually do in R. Say, we wanted to save above output to some data frame.

rr flight_sub=flights %>% select(Distance, AirTime) %>% mutate(Speed = Distance/AirTime*60)



4.5 Summarizing Data

We are done with data wrangling without collapsing it. Next we look at exactly that, summarising data by groups or collapsing data to its group wise summaries using dplyr.

rr # dplyr approach: create a table grouped by Dest, and then summarise each group by taking the mean of ArrDelay flights %>% group_by(Dest) %>% summarise(avg_delay = mean(ArrDelay, na.rm=TRUE))


This pretty much finishes our discussion on dplyr verbs and adverbs. We have given few more examples to learn new useful functionalities which we havent been introduced yet.

For each day of the year, count the total number of flights and sort in descending order

rr # for each day of the year, count the total number of flights and sort in descending order z=flights %>% group_by(Month, DayofMonth) %>% summarise(flight_count = n()) %>% arrange(desc(flight_count))


Lets rewrite more simply with the tally function

rr # rewrite more simply with the ‘tally’ function flights %>% group_by(Month, DayofMonth) %>% tally(sort = TRUE)


For each destination, count the total number of flights and the number of distinct planes that flew there.

rr # for each destination, count the total number of flights and the number of distinct planes that flew there flights %>% group_by(Dest) %>% summarise(flight_count = n(), plane_count = n_distinct(TailNum))


For each destination, show the number of cancelled and not cancelled flights.

rr # For each destination, show the number of cancelled and not cancelled flights flights %>% group_by(Dest) %>% select(Cancelled) %>% table() %>% head()

Adding missing grouping variables: `Dest`
     Cancelled
Dest     0    1
  ABQ 2787   25
  AEX  712   12
  AGS    1    0
  AMA 1265   32
  ANC  125    0
  ASE  120    5

For each month, calculate the number of flights and the change from the previous month.

rr # for each month, calculate the number of flights and the change from the previous month flights %>% group_by(Month) %>% summarise(flight_count = n()) %>% mutate(change = flight_count - lag(flight_count))


Again, lets rewrite more simply with the tally function.

rr # rewrite more simply with the tally function flights %>% group_by(Month) %>% tally() %>% mutate(change = n - lag(n))


Base R approach to view the structure of an object

rr # base R approach to view the structure of an object str(flights)

Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   227496 obs. of  22 variables:
 $ Year             : int  2011 2011 2011 2011 2011 2011 2011 2011 2011 2011 ...
 $ Month            : int  1 1 1 1 1 1 1 1 1 1 ...
 $ DayofMonth       : int  1 2 3 4 5 6 7 8 9 10 ...
 $ DayOfWeek        : int  6 7 1 2 3 4 5 6 7 1 ...
 $ DepTime          : int  1400 1401 1352 1403 1405 1359 1359 1355 1443 1443 ...
 $ ArrTime          : int  1500 1501 1502 1513 1507 1503 1509 1454 1554 1553 ...
 $ UniqueCarrier    : chr  \AA\ \AA\ \AA\ \AA\ ...
 $ FlightNum        : int  428 428 428 428 428 428 428 428 428 428 ...
 $ TailNum          : chr  \N576AA\ \N557AA\ \N541AA\ \N403AA\ ...
 $ ActualElapsedTime: int  60 60 70 70 62 64 70 59 71 70 ...
 $ AirTime          : int  40 45 48 39 44 45 43 40 41 45 ...
 $ ArrDelay         : int  -10 -9 -8 3 -3 -7 -1 -16 44 43 ...
 $ DepDelay         : int  0 1 -8 3 5 -1 -1 -5 43 43 ...
 $ Origin           : chr  \IAH\ \IAH\ \IAH\ \IAH\ ...
 $ Dest             : chr  \DFW\ \DFW\ \DFW\ \DFW\ ...
 $ Distance         : int  224 224 224 224 224 224 224 224 224 224 ...
 $ TaxiIn           : int  7 6 5 9 9 6 12 7 8 6 ...
 $ TaxiOut          : int  13 9 17 22 9 13 15 12 22 19 ...
 $ Cancelled        : int  0 0 0 0 0 0 0 0 0 0 ...
 $ CancellationCode : chr  \\ \\ \\ \\ ...
 $ Diverted         : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Speed            : num  336 299 280 345 305 ...

dplyr approach: better formatting, and adapts to your screen width.

glimpse(flights)
Error in glimpse(flights) : could not find function "glimpse"
In addition: Warning message:
In scan(file = file, what = what, sep = sep, quote = quote, dec = dec,  :
  EOF within quoted string


5. Sampling Data

As moving slowly towards predictive modelling, you’d need to take randome sample from your data for different purposes. You can achieve that in a rather simple manner by using the function sample which we have used a lot so far. Here goes an example for taking 70% random data from data frame mtcars.

rr # we are using set.seed for our random sample to be reproducible set.seed(1) s=sample(1:nrow(mtcars),0.7*nrow(mtcars))


You can now use this vector s as row index vector to take sample data from the data frame.

rr mtcars_sample=mtcars[s,]


How do I get the rest of the observations which are not in sample taken above?

rr mtcars_remaining=mtcars[-s,]


How to randomly bootstrap your data? Again, you can achieve that by using sampling with replacement with function sample

rr set.seed(1) s=sample(1:nrow(mtcars),100,replace = TRUE) mtcars_bootstrapped=mtcars[s,]

LS0tDQp0aXRsZTogIkRhdGEgTWFuaXB1bGF0aW9uIHdpdGggZHBseXIiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNQ0KLS0tDQoNCiMgMS4gSW50cm9kdWN0aW9uIHRvIERhdGEgUHJlcGFyYXRpb24NCg0KKipEYXRhIHByZXBhcmF0aW9uKiogaXMgdGhlIHZlcnkgZmlyc3QgdGhpbmcgdGhhdCB5b3UgZG8gYW5kIHNwZW5kIGEgbG90IG9mIHRpbWUgb24gYXMgYSBkYXRhIGFuYWx5c3QgbXVjaCBiZWZvcmUgdHJ5aW5nIHRvIGJ1aWxkIHByZWRpY3RpdmUgbW9kZWxzIHVzaW5nIHRoYXQgZGF0YS4NCg0KSW4gZXNzZW5jZSBkYXRhIHByZXBhcmF0aW9uIGlzIGFsbCBhYm91dCBwcm9jZXNzaW5nIGRhdGEgdG8gZ2V0IGl0IHJlYWR5IGZvciBhbGwga2luZHMgb2YgYW5hbHlzaXMuIEluIGluZHVzdHJ5IGRhdGEgY29sbGVjdGlvbiBpcyBtb3N0bHkgZHJpdmVuIGJ5IGJ1c2luZXNzIHByb2Nlc3MgYXQgZnJvbnQsIG5vdCBieSB0aGUgbmVlZHMgb2YgcHJlZGljdGl2ZSBtb2RlbHMuIFRoZXNlIHZhcmlvdXMgcHJvY2Vzc2VzIGF0IHNvbWUgb3IgdGhlIG90aGVyIHBvaW50IGJlY29tZSByZWFzb24gZm9yIGludHJvZHVjdGlvbiBvZiBlcnJvcnMgaGVyZSBhbmQgdGhlcmUgaW4gdGhlIGRhdGEuDQoNCjxjZW50ZXI+DQoNCiFbXShgciAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2luc2FpZDIwMTgvUi9tYXN0ZXIvaW1hZ2VzL2RhdGElMjBwcmVwYXJhdGlvbi5qcGciYCl7d2lkdGg9NTAlfQ0KDQo8L2NlbnRlcj4NCg0KX19fDQoNCiMgMi4gRGF0YSBQcm9jZXNzaW5nDQoNClRoZXJlIGNhbiBiZSBtYW55IGtpbmQgb2YgcmVhc29ucyBub3QgbmVjZXNzYXJpbHkgZXJyb3JzIGZvciB3aGljaCB3ZSB3b3VsZCBuZWVkIHRvICoqcHJlLXByb2Nlc3MqKiBvdXIgZGF0YSBhbmQgY2hhbmdlIGl0IGZvciBiZXR0ZXIuDQoNCiogTWlzc2luZyBkYXRhDQoqIFBvdGVudGlhbGx5IGluY29ycmVjdCBkYXRhDQoqIE5lZWQgZm9yIGNoYW5naW5nIGZvcm0gb2YgdGhlIGRhdGENCg0KIyMgMi4xIExvYWQgTGlicmFyaWVzIGFuZCBQYWNrYWdlcw0KDQpMZXRzIGJlZ2luIHdpdGggaW1wb3J0aW5nIGFsbCB0aGUgcmVsZXZhbnQgKipsaWJyYXJpZXMqKiBhbmQgKipwYWNrYWdlcyoqLg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHBzeWNoKQ0KbGlicmFyeSh2Y2QpDQpgYGANCg0KIyMgMi4yIEltcG9ydGluZyBEYXRhDQoNCldlIGFyZSBnb2luZyB0byBpbXBvcnQgZGF0YSBmaWxlICoqYmFuay1mdWxsLmNzdioqIGhlcmUuIExldHMgYmVnaW4sIHdlJ2xsIHN0YXJ0IHdpdGggcGFzc2luZyBqdXN0IHRoZSBmaWxlIG5hbWUgYW5kIGxldCBhbGwgb3RoZXIgYmUgb3B0aW9uIHRha2UgdGhlaXIgZGVmYXVsdHMuIFdlJ2xsIGNoYW5nZSBzb21lIGFzIHdlIGNvbWUgYWNyb3NzIGlzc3VlIHdpdGggdGhlIGltcG9ydGVkIGRhdGEuDQoNCmBgYHtyfQ0KYmQgPSByZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2luc2FpZDIwMTgvUi9tYXN0ZXIvRGF0YS9iYW5rLWZ1bGwuY3N2IikNCmhlYWQoYmQsMikNCmBgYA0KDQpfX18NCg0KIyMgMi4zIFJlYWRpbmcgRGF0YQ0KDQpZb3UgY2FuIHNlZSB0aGF0IHdlIGhhdmUgYmVlbiBmb29sZWQgYnkgdGhlIGZpbGUgZXh0ZW5zaW9uIGFuZCBhc3N1bWVkIHRoYXQgdGhlIHNlcGFyYXRvciBmb3IgdGhlIGRhdGEgaXMgIGNvbW1hIHdoZXJlIGFzIGluIHJlYWxpdHkgaXQgaXMgIjsiLiBMZXRzIHRlbGwgdGhhdCB0byBSIGJ5IHVzaW5nIG9wdGlvbiAqKnNlcCoqLg0KDQpgYGB7cn0NCmJkID0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9pbnNhaWQyMDE4L1IvbWFzdGVyL0RhdGEvYmFuay1mdWxsLmNzdiIsIHNlcD0iOyIpDQpoZWFkKGJkLDIpDQpgYGANCg0KX19fDQoNCk9rYXksIHRoaXMgbG9va3MgYmV0dGVyLiBOb3csIGxldHMgbG9vayBhdCBvdXIgZGF0YS4NCg0KYGBge3J9DQpnbGltcHNlKGJkKQ0KYGBgDQoNCl9fXw0KDQpXZSBjYW4gYWxzbyBjb21wdXRlIHRoZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHVzaW5nIHRoZSAqKmRlc2NyaWJlKiogZnVuY3Rpb24gYXZhaWxhYmxlIGluICoqcHN5Y2gqKiBwYWNrYWdlLiANCg0KYGBge3J9DQpkZXNjcmliZShiZCkNCmBgYA0KDQpfX18NCg0KTGV0cyBsb29rIGF0IHRoZSAqKjYgcG9pbnQqKiBzdW1tYXJ5IG9mIG91ciBkYXRhIHVzaW5nIHRoZSAqKnN1bW1hcnkqKiBmdW5jdGlvbi4NCg0KYGBge3J9DQpzdW1tYXJ5KGJkKQ0KYGBgDQoNCl9fXw0KDQojIyAyLjQgQ2hhbmdpbmcgRGF0YSBUeXBlcw0KDQpZb3UgY2FuIHNlZSB0aGF0IGFsbCBvZiBvdXIgY2hhcmFjdGVyIGNvbHVtbnMgaGF2ZSBiZWVuIHN0b3JlZCBhcyBmYWN0b3JzLiBUaGlzIG5lZWRzIHRvIGJlIGF2b2lkZWQuIEFuZCB3ZSBjYW4gZG8gc28gYnkgdXNpbmcgb3B0aW9uICoqc3RyaW5nc0FzRmFjdG9ycyoqLiANCg0KYGBge3J9DQpiZD1yZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2luc2FpZDIwMTgvUi9tYXN0ZXIvRGF0YS9iYW5rLWZ1bGwuY3N2Iiwgc2VwPSI7IixzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpnbGltcHNlKGJkKQ0KYGBgDQpfX18NCg0KIyMgMi41IEhhbmRsaW5nIE1pc3NpbmcgRGF0YQ0KDQpOZXh0LCBsZXRzIGxvb2sgYXQgd2hhdCB2YWx1ZXMgb3VyIHZhcmlhYmxlIGpvYiB0YWtlcy4NCg0KYGBge3J9DQp0YWJsZShiZCRqb2IpDQpgYGANCg0KVGhlcmUgYXJlIDI4OCBvYnNlcnZhdGlvbnMgd2hlcmUgdGhlIHZhbHVlIGlzIHVua25vd24sIGlmIHlvdSB3YW50LCB5b3UgY2FuIHNldCBpdCB0byBtaXNzaW5nIGJ5IHVzaW5nIG9wdGlvbiAqKm5hLnN0cmluZ3MqKi4gQnV0LCByZW1lbWJlciB0aGlzIHdpbGwgc2V0IHRoZSB2YWx1ZSB1bmtub3duIGFzIG1pc3NpbmcgZm9yIGFsbCB0aGUgY29sdW1ucy4gSWYNCnlvdSB3YW50IHRvIGRvIGl0IG9ubHkgZm9yIG9uZSBvZiBjb2x1bW5zIHRoZW4gZG8gdGhhdCBhZnRlciB5b3UgaGF2ZSBpbXBvcnRlZCB0aGUgZGF0YS4NCg0KYGBge3J9DQpiZD1yZWFkLmNzdigiYmFuay1mdWxsLmNzdiIsc2VwPSI7IixzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsbmEuc3RyaW5ncyA9ICJ1bmtub3duIikNCnN1bShpcy5uYShiZCRqb2IpKQ0KYGBgDQoNCllvdSBjYW4gc2VlIHRoYXQsIG5vdyBjb2x1bW4gam9iIGhhcyAyODggbWlzc2luZyB2YWx1ZXMuIFRoaXMgd2FzIHRvIHNob3cgeW91IGhvdyB0byB1c2Ugb3B0aW9uIG5hLnN0cmluZy4gSW4gZ2VuZXJhbCBpdCBpcyBub3QgYSBnb29kIHByYWN0aWNlIHRvIHNldCBhbnkgcmFuZG9tIHZhbHVlIGFzIG1pc3NpbmcuIFNvLCBmb3IgcHJhY3RpY2UgaXRzIGFscmlnaHQsIGJ1dCBkb250IHNldCB1bmtub3duIHRvIG1pc3NpbmcgaW4gZ2VuZXJhbCB1bmxlc3MgeW91IGhhdmUgZ29vZCByZWFzb24gdG8gZG8gc28uIEluIGZhY3QgaW4gbWFueSBvZiB0aGUgY2FzZXMgb2YgY2F0ZWdvcmljYWwgdmFyaWFibGVzLCB1bmtub3duIGl0c2VsZiBjYW4gYmUgdGFrZW4gYXMgYSB2YWxpZCBjYXRlZ29yeSBhcyB5b3UnbGwgcmVhbGlzZSBsYXRlci4NCg0KV2UgZG9udCBuZWVkIHRvIGNoYW5nZSBkZWZhdWx0IHZhbHVlcyBvZiBvdGhlciBvcHRpb25zIGZvciB0aGlzIGltcG9ydGluZy4gU2FtZSB3aWxsIGJlIHRoZSBjYXNlIGZvciB5b3UgYXMgd2VsbCBmb3IgbW9zdCBvZiB0aGUgZGF0YS4gSWYgaXQgaXMgbm90LCBmZWVsIGZyZWUgdG8gdXNlIGFueSBvZiB0aGUgb3B0aW9uIGRlc2NyaWJlZCBhYm92ZS4NCg0KX19fDQpfX18NCg0KIyAzLiBEYXRhIE9wZXJhdGlvbnMNCg0KV2UnbGwgc3RhcnQgd2l0aCBkaXNjdXNzaW9uIG9uIGFwcGx5IGZhbWlseSBvZiBmdW5jdGlvbnMgd2hpY2ggYXJlIHZlcnkgaGFuZHkgd2F5IHRvIHN1bW1hcml6ZSBhcyB3ZWxsIGFzIGRvIG90aGVyIG9wZXJhdGlvbnMgY29sbGVjdGl2ZWx5IG9uIHlvdXIgZGF0YS4gTGV0cyBzYXkgd2Ugd2FudCB0byBnZXQgbWVhbnMgb2YgYWxsIGNvbHVtbnMgcHJlc2VudCBpbiB0aGUgZGF0YSBtdGNhcnMuIFdlIGNvdWxkIGFjaGlldmUgdGhhdCB3cml0aW5nIGEgZm9yIGxvb3AgYWNyb3NzIGNvbHVtbnMgd2l0aCBmdW5jdGlvbiBtZWFuLg0KDQpgYGB7cn0NCmZvcihpIGluIDE6bmNvbChtdGNhcnMpKXsNCnByaW50KG1lYW4obXRjYXJzWyxpXSkpDQp9DQpgYGANCg0KX19fDQoNCkZpbmUgeW91IGdldCB0aGUgcmVzdWx0LCBidXQgaXRzIG5vdCBpbiBhIHZlcnkgY29udmVuaWVudCBmb3JtYXQgYW5kIGNvZGUgaXMgbm90IHByZXR0eS4gV2hhdCBpZiB0aGVyZSBleGlzdHMgYSBmdW5jdGlvbiB3aGljaCBsZXRzIHVzIGRvIHRoaXMgd2l0aG91dCB3cml0aW5nIHRoZXNlIGxvb3BzIGFuZCBoYXZpbmcgdG8gZ28gdGhyb3VnaCBtYW5hZ2luZyBpdGVyYXRpb25zIGZvciBhIGZ1bmN0aW9uLiBUaGlzIGlzIHN1Y2ggYSBjb21tb24gc2NlbmFyaW8gaW4gZGF0YSBwcm9jZXNzaW5nLCBSIGhhcyBhIGZhbWlseSBvZiBkZWRpY2F0ZWQgZnVuY2l0b25zIGZvciB0aGlzLg0KDQpgYGB7cn0NCng9cm91bmQocm5vcm0oMTApLDIpDQp4DQpgYGANCg0KX19fDQpfX18NCg0KIyMgMy4xIEFwcGx5IEZ1bmN0aW9ucw0KDQpXZSdsbCBmaXJzdCB0YWxrIGFib3V0ICoqbGFwcGx5KiouIFRoaXMgbGV0cyB5b3UgYXBwbHkgYSBmdW5jdGlvbiByZXBlYXRlZGx5IG9uIGEgbGlzdC92ZWN0b3IsIHRoZSBvdXRjb21lIGlzIGEgbGlzdCBvZiByZXN1bHRzLiBMZXRzIHNlZSBhbiBleGFtcGxlLg0KDQpgYGB7cn0NCmxhcHBseSh4LGxvZzEwKQ0KYGBgDQoNCkJ1dCBhYm92ZSBvcGVyYXRpb24gY2FuIGJlIGVhc2lseSBhY2hpZXZlZCB1c2luZyB2ZWN0b3Igb3BlcmF0aW9ucy4gSW5mYWN0IGEgc2ltcGxlICoqbG9nKHgpKiogd2lsbCBnaXZlIHlvdSB0aGUgc2FtZSByZXN1bHQgYW5kIGluIGEgbXVjaCB1c2FibGUgZm9ybWF0IGFzIHdlbGwuIEJ1dCB0aGVuIHdoYXQgZ29vZCBpcyB0aGlzICoqbGFwcGx5KiogdGhpbmc/IA0KDQpMZXRzIHB1dCBpdCB0byBhIGJldHRlciB1c2UgYW5kIHdpdGggbW9yZSBvcHRpb25zLiBIb3cgYWJvdXQsIGlmIHlvdSBoYWQgYSBsb3Qgb2YgdGV4dCBmaWxlcyBpbiB5b3VyIGZvbGRlciBhbmQgeW91IHdhbnRlZCB0byBpbXBvcnQgdGhlbSBhbGwuIE9uZSBzb2x1dGlvbiB3aWxsIGJlIHRvIHdyaXRlIG9uZSBsaW5lIG9mICoqcmVhZC5jc3YqKiBmb3IgYWxsIHRoZXNlIGZpbGVzIG9yIG1heSBiZSB5b3UgY2FuIHJ1biBhIGxvb3AuIEJldHRlciB5b3UgY291bGQgcGFzcyBhbGwgdGhvc2UgbmFtZXMgdG8gZnVuY3Rpb24gKipyZWFkLmNzdioqIHVzaW5nICoqbGFwcGx5KiouDQoNCmBgYHtyfQ0KIyBCZWZvcmUgcnVubmluZyB0aGVzZSBjb2RlcyAsIHlvdSdsbCBoYXZlIHRvIHNldCB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5IHRvIHRoZSBmb2xkZXIgIm5hbWVzYnlzdGF0ZSIuDQoNCmZpbGVfbmFtZXMgPSBsaXN0LmZpbGVzKGdldHdkKCksIHBhdHRlcm4gPSAiKi5UWFQiKQ0KDQpmaWxlcyA9IGxhcHBseShmaWxlX25hbWVzLCByZWFkLmNzdiwgaGVhZGVyID0gRiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpDQpgYGANCg0KX19fDQoNClNlZSwgd2UgY2FuIHBhc3Mgb3RoZXIgY29tbW9uIG9wdGlvbnMgdG8gZnVuY3Rpb24gcmVhZC5jc3YgaW4gbGFwcGx5LiBGaWxlIG5hbWVzIGluIHRoZSBvYmplY3QgKipmaWxlX25hbWVzKiogYXJlIHBhc3NlZCBvbmUgYnkgb25lIHRvIGZ1bmN0aW9uIHJlYWQuY3N2LiBUaGUgb3V0cHV0IGZpbGUgaXMgc2ltcGx5IGEgbGlzdCBvZiBkYXRhIGZyYW1lcy4gSWYgeW91IHdhbnQgdG8gY29tYmluZSB0aGVtLCB5b3UgY2FuIGRvIHNvIGJ5IHVzaW5nIGZ1bmN0aW9uICoqZG8uY2FsbCoqLg0KDQpgYGB7cn0NCmZpbGUgPSBkby5jYWxsKHJiaW5kLGZpbGVzKQ0KYGBgDQoNCioqZG8uY2FsbCoqIGhlcmUgcGFzc2VzIGFsbCB0aGUgZWxlbWVudHMgaW4gdGhlIHNlY29uZCBhcmd1bWVudCB0byBmdW5jdGlvbiBtZW50aW9uZWQgaW4gZmlyc3QgYXJndW1lbnQuDQoNCl9fXw0KDQpJbiBqdXN0IHRocmVlIHNpbXBsZSBsaW5lcyBvZiBjb2RlLCB3ZSBoYXZlIHJlYWQgZGF0YSBmcm9tIDUwKyBmaWxlcyBhbmQgY29tYmluZWQgaXQgaW50byBvbmUuIEluIGp1c3QgdGhyZWUgbGluZXMhIEFsbCB0aGFua3MgdG8gKipsYXBwbHkqKi4gQXQgdGltZXMgdGhlIG91dHB1dCBpbiBmb3JtIG9mIGEgbGlzdCBiZWNvbWVzIGRpZmZpY3VsdCB0byBoYW5kbGUuDQoNCllvdSBjYW4gdXNlICoqc2FwcGx5KiogaW4gdGhlc2UgY2FzZXMuIHNhcHBseSB3b3JrcyBleGFjdGx5IGxpa2UgbGFwcGx5LCBvbmx5IGRpZmZlcmVuY2UgYmVpbmcsIGl0IHRyaWVzIHRvIHZlY3RvcmlzZSBvdXRwdXQgb2YgbGFwcGx5IGlmIGl0IGlzIHBvc3NpYmxlLg0KDQpgYGB7cn0NCnNhcHBseSh4LCBsb2cpDQpgYGANCg0KX19fDQoNCkNvbWluZyBiYWNrIHRvIG91ciBmaXJzdCBwcm9ibGVtIG9mIGdldHRpbmcgbWVhbiBmb3IgYWxsIGNvbHVtbnMuIFllcywgeW91IGNhbiB1c2UgbGFwcGx5LCBiZWNhdXNlIGRhdGENCmZyYW1lcyBhcmUgbm90aGluZyBidXQgbGlzdCBvZiB2ZWN0b3JzLiBUaGVyZSBpcyBhbm90aGVyIGZ1bmN0aW9uIGluIGFwcGx5IGZhbWlseSBuYW1lZCBhcHBseSB3aGljaCBwcm92aWRlcyBiZXR0ZXIgb3V0cHV0IGFuZCBhIGxpdHRsZSBtb3JlIGZ1bmNpdG9uYWxpdHkgd2hlbiB5b3Ugd2FudCB0byBhcHBseSBmdW5jdGlvbiBpdGVyYXRpdmVseSBvbiBkYXRhIGZyYW1lIGVsZW1lbnRzLg0KDQpgYGB7cn0NCmFwcGx5KG10Y2FycywyLG1lYW4pDQpgYGANCg0KVGhlIGZpcnN0IGFyZ3VtZW50IHRvIGFwcGx5IGlzIHRoZSBuYW1lIG9mIHRoZSBkYXRhIGZyYW1lLiBUaGlyZCBhcmd1bWVudCBpcyB0aGUgZnVuY3Rpb24gd2hpY2ggaXMgZ29pbmcgdG8gZ2V0IGFwcGxpZWQuIFNlY29uZCBhcmd1bWVudCB0YWtlcyB0d28gdmFsdWVzOiBbMSBvciAyXS4gMSBzdGFuZHMgZm9yIHJvd3MgYW5kIDIgZm9yIGNvbHVtbnMuIFdoaWNoIG1lYW5zLCBpZiB5b3UgcHV0IDIgaW4gdGhlIHNlY29uZCBhcmd1bWVudCwgZnVuY3Rpb24gaW4gdGhlIHRoaXJkIGFyZ3VtZW50IHdpbGwgYmUgYXBwbGllZCBvbiB0aGUgY29sdW1ucyBvZiB0aGUgZGF0YSBmcmFtZXMuIElmIHRoZSB2YWx1ZSBpcyBnaXZlbiBhcyAxLCBmdW5jdGlvbiBnZXRzIGFwcGxpZWQgb24gcm93cy4NCg0KX19fDQoNCkZ1bmN0aW9ucyB3aGljaCB5b3UgcGFzcyB0byBhcHBseSBhcmUgbm90IGxpbWl0ZWQgdG8gcHJlIGV4aXN0aW5nIGZ1bmN0aW9uIGluIFIuIFlvdSBjYW4gd3JpdGUgeW91ciBvd24gYW5kIHBhc3MgaXQgdG8gYXBwbHkgZmFtaWx5IGZ1bmN0aW9ucy4gTGV0cyB3cml0ZSBhIGZ1bmN0aW9uIHdoaWNoIHJldHVybnMgdXBwZXIgbGltaXQgb2Ygb3V0bGllcnMgZ2l2ZW4gYSB2YXJpYWJsZSBjb2x1bW4uDQoNCmBgYHtyfQ0Kb3V0bGllcl91cHBlcj1mdW5jdGlvbih4KXsNCm09bWVhbih4KTsNCnM9c2QoeCk7DQpyZXR1cm4obSszKnMpOw0KfQ0KYXBwbHkobXRjYXJzLDIsb3V0bGllcl91cHBlcikNCmBgYA0KDQpfX18NCg0KV2hhdCB5b3UgbmVlZCB0byByZW1lbWJlciBoZXJlIGlzIHdoYXQgZ29lcyBhcyBpbnB1dCB0byB0aGUgZnVuY3Rpb24uIEluIGNhc2Ugb2YgYXBwbHksIGlucHV0IGlzIHRoZSBlbnRpcmUgcm93IG9yIGNvbHVtbi4gTGV0cyB1c2UgYXBwbHkgdG8gZmluZCBvdXQgaG93IG1hbnkgb3V0bGllcnMgZWFjaCBjb2x1bW4gaGFzIGFjY29yZGluZyB0byBmdW5jdGlvbiBvdWxpZXJfdXBwZXIuDQoNCmBgYHtyfQ0KYXBwbHkobXRjYXJzLDIsZnVuY3Rpb24oeCkgc3VtKHg+b3V0bGllcl91cHBlcih4KSkpDQpgYGANCg0KX19fDQoNCldoYXQgaWYgeW91IHdhbnQgdG8gZ2V0IGEgZ3JvdXAgd2lzZSBzdW1tYXJ5IG9mIGFueSB2YXJpYWJsZS4gKip0YXBwbHkqKiBjb21lcyB0byB5b3VyIHJlc2N1ZS4gRmlyc3QgYXJndWVtZW50IHRvIHRhcHBseSBpcyB0aGUgY29sdW1uIGZvciB3aGljaCB3ZSBhcmUgbG9va2luZyBmb3Igc3VtbWFyeSwgc2Vjb25kIGFyZ3VtZW50IGlzIHRoZSBncm91cGluZyB2YXJpYWJsZSwgdGhpcmQgYXJndW1lbnQgaXMgdGhlIGZ1bmN0aW9uIHdoaWNoIHdpbGwgYmUgYXBwbGllZCBvbiB0aGUgZ3JvdXBzLg0KDQpgYGB7cn0NCnRhcHBseShtdGNhcnMkbXBnLG10Y2FycyRhbSxtZWFuKQ0KYGBgDQoNCl9fXw0KDQpGb3IgZ2V0dGluZyBncm91cCB3aXNlIHN1bW1hcnkgb2YgYWxsIHRoZSB2YXJpYWJsZSBpbiB0aGUgZGF0YXNldCBtdGNhcnMgeW91IGNhbiB1c2UgYSBjb21iaW5hdGlvbiBvZiAqKmFwcGx5KiogYW5kICoqdGFwcGx5KiouDQoNCmBgYHtyfQ0KYXBwbHkobXRjYXJzLDIsZnVuY3Rpb24oeCkgdGFwcGx5KHgsbXRjYXJzJGFtLG1lYW4pKQ0KYGBgDQoNCl9fXw0KX19fDQoNCiMjIDMuMiBBZGRpbmcgVmFyaWFibGVzIA0KDQpDcmVhdGluZyB2YXJpYWJsZXMvdmVjdG9ycyB3aXRoIHNpbXBsZSBhbGdlYnJhaWMgb3BlcmF0aW9ucyBpcyBzdHJhaWdodCBmb3J3YXJkLiBMZXRzIGFkZCBvbmUgdmFyaWFibGUgdG8gZGF0YSBmcmFtZSBBcnRocml0aXMuDQoNCmBgYHtyfQ0KQXJ0aHJpdGlzJG5ldz1sb2coQXJ0aHJpdGlzJEFnZSkNCmhlYWQoQXJ0aHJpdGlzKQ0KYGBgDQoNCl9fXw0KDQpXaGF0IGlmIHdlIHdhbnRlZCB0byBjcmVhdGUgYW4gaW5kaWNhdG9yIHZhcmlhYmxlIHdoaWNoIHRha2VzIHZhbHVlIDAgb3IgMSBhY2NvcmRpbmcgdG8gQWdlIGJlaW5nIGxlc3MgdGhhbiBvciBncmVhdGVyIHRoYW4gNDA/IFRoZXNlIHNpbXBsZSBhbGdlYnJhaWMgb3BlcmF0aW9ucyB3aWxsIG5vdCB3b3JrLiBXZSdsbCBoYXZlIHRvIHVzZSBjb25kaXRpb25hbCBvcGVyYXRvcnMuDQoNCmBgYHtyfQ0KQXJ0aHJpdGlzJG5ldz1hcy5udW1lcmljKEFydGhyaXRpcyRBZ2U8NDApDQpoZWFkKEFydGhyaXRpcykNCmBgYA0KDQpfX18NCg0KVGhpcyBzZWVtcyB0cml2aWFsIHRvbywgbm93IHdoYXQgaWYgd2Ugd2FudCAqKkFnZSoqIHRvIGJlIGZsb29yZWQgdG8gNDAgd2hlbmV2ZXIgaXQgaXMgbGVzcyB0aGFuIDQwIGFuZCBvdGhlciB3aXNlIGtlcHQgYXMgaXQgaXMuIFdlIHdvbnQgYmUgYWJsZSB0byBhY2hpZXZlIHRoaXMgd2l0aCBzaW1wbGUgY29uZGl0aW9uYWwgc3RhdGVtZW50IGVpdGhlci4gDQoNCmBgYHtyfQ0KeCA9IHNhbXBsZSg0MCwxMCkNCngNCmBgYA0KDQpfX18NCg0KV2Ugd2lsbCBiZSB1c2luZyBmdW5jdGlvbiAqKmlmZWxzZSoqIHRvIGFjaGlldmUgdGhlIHNhbWUuDQoNCmBgYHtyfQ0KeSA9IGlmZWxzZSh4PjIwLDIwLHgpDQp5DQpgYGANCg0KX19fDQoNCk5vdywgbGV0cyB1c2UgdGhpcyB0byBhZGQgYSB2YXJpYWJsZSBpbiB0aGUgZGF0YSBmcmFtZS4NCg0KYGBge3J9DQpBcnRocml0aXMkbmV3ID0gaWZlbHNlKEFydGhyaXRpcyRBZ2U8NDAsIDQwLCBBcnRocml0aXMkQWdlKQ0KaGVhZChBcnRocml0aXMpDQpgYGANCg0KX19fDQpfX18NCg0KIyA0LiBEYXRhIFdyYW5nbGluZw0KDQpXZSBoYXZlIHNlZW4gd2F5cyB0byBtb2RpZnkgYW5kIHN1bW1hcmlzZSBkYXRhIGluIGJhc2UgUi4gQWdhaW4gdGhvc2UgZnVuY3Rpb25hbGl0aWVzIGFyZSBraW5kIG9mIHNjYXR0ZXJlZCBhbmQgbm90IHN0cmVhbWxpbmVkLiBJZiB5b3UgdGhpbmsgYWJvdXQgaXQgeW91IGNhbiBhY2hpZXZlIGFsbW9zdCBhbGwga2luZCBvZiBtb2RpZmljYXRpb25zIHRvIGRhdGEgdXNpbmcgdGhlc2UgdmVyYnM6DQoNCiogKipmaWx0ZXIqKjogY29uZGl0aW9uYWwgZmlsdGVyaW5nIG9mIGRhdGENCiogKipzZWxlY3QqKjogc2VsZWN0aW5nIGNvbHVtbnMNCiogKiptdXRhdGUqKjogYWRkaW5nL21vZGlmeWluZyBjb2x1bW5zDQoqICoqYXJyYW5nZSoqOiBzb3J0aW5nIGNvbHVtbnMNCiogKipzdW1tYXJpc2UqKiAod2l0aCBhZHZlcmIgZ3JvdXBfYnkpOiBDb2xsYXBzaW5nIGRhdGEgdG8gaXRzIHN1bW1hcmllcw0KDQpQYWNrYWdlICoqZHBseXIqKiBjb21lcyB3aXRoIHRoZXNlIHZlcmJzIGZvciBkYXRhIHdyYW5nbGluZy4gTmV4dCwgd2UnbGwgc2VlIGhvdyB0byBhY2hpZXZlIGRpZmZlcmVudCBkYXRhIHdyYW5nbGluZyB0YXNrIGluIGJhc2UgUiBhbmQgdGhlIHNhbWUgaW4gZHBseXIuIE9mIGNvdXJzZSBkcGx5ciBjb21lcyB3aXRoIHNvbWUgYWRkdGlvbmFsIGZ1Y3Rpb25sYWl0aWVzIHRvbyBhbmQgd2UnbGwgYmUgbG9va2luZyBhdCB0aG9zZSBhcyB3ZWxsLiANCg0KQmVmb3JlIHdlIHN0YXJ0LCBpbnN0YWxsIHBhY2thZ2VzICoqZHBseXIqKiBhbmQgKipoZmxpZ2h0cyoqLiANCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShoZmxpZ2h0cykNCmBgYA0KDQpfX18NCg0KV2UnbGwgYmUgdXNpbmcgZGF0YSBzZXQgKipoZmxpZ2h0cyoqLiBZb3UgY2FuIGdldCBkZXRhaWxzIG9mIHRoZSBkYXRhICoqaGZsaWdodHMqKiBhZnRlciB5b3UgaGF2ZSBsb2FkZWQgbGlicmFyeSAqKmhmbGlnaHRzKiogYnkgdHlwaW5nICoqP2hmbGlnaHRzKiouDQoNCmBgYHtyfQ0KP2hmbGlnaHRzDQpgYGANCg0KX19fDQoNCkxldHMgaGF2ZSBhIGxvb2sgYXQgb3VyIGRhdGEuDQoNCmBgYHtyfQ0KZGF0YShoZmxpZ2h0cykNCmhlYWQoaGZsaWdodHMpDQpgYGANCg0KX19fDQoNCldlJ2xsIHN0YXJ0IHdpdGggb3VyIGZpcnN0IGZ1bmN0aW9uICoqdGJsX2RmKiogd2hpY2ggY29udmVydHMgYSBkYXRhLmZyYW1lIHRvIGEgdGFidWxhciBmb3JtYXQgZm9yIHdoaWNoIGRpc3BsYXkgb24gY29uc29sZSBpcyBiZXR0ZXIuIEl0IGNoYW5nZXMgbm90aGluZyBlbHNlIGFib3V0IHRoZSBkYXRhIGZyYW1lLg0KDQpgYGB7cn0NCmZsaWdodHMgPSB0YmxfZGYoaGZsaWdodHMpDQpmbGlnaHRzDQpgYGANCg0KX19fDQoNCiMjIDQuMSBGaWx0ZXIgRGF0YQ0KDQpMZXRzIGxvb2sgYXQgY29uZGl0aW9uICoqZmlsdGVyaW5nKiogb2YgdGhlIGRhdGEuIFdlJ2xsIHN0YXJ0IHdpdGggYmFzZSBSIGFwcHJvYWNoIHRvIHZpZXcgYWxsIGZsaWdodHMgb24gSmFudWFyeSAxDQoNCmBgYHtyfQ0KZmxpZ2h0c1tmbGlnaHRzJE1vbnRoPT0xICYgZmxpZ2h0cyREYXlvZk1vbnRoPT0xLF0NCmBgYA0KDQpfX18NCg0KIyMjIDQuMS4xICoqZHBseXIqKiBBcHByb2FjaA0KDQpZb3UgY2FuIHVzZSAqKmNvbW1hKiogb3IgKiphbXBlcnNhbmQqKiB0byByZXByZXNlbnQgKipBTkQqKiBjb25kaXRpb24NCg0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgTW9udGg9PTEsIERheW9mTW9udGg9PTEpDQpgYGANCg0KX19fDQoNCllvdSBjYW4gdXNlICoqcGlwZSoqIGZvciAqKk9SKiogY29uZGl0aW9uDQoNCmBgYHtyfQ0KZmlsdGVyKGZsaWdodHMsIFVuaXF1ZUNhcnJpZXI9PSJBQSIgfCBVbmlxdWVDYXJyaWVyPT0iVUEiKQ0KYGBgDQoNCl9fXw0KDQpZb3UgY2FuIGFsc28gdXNlICoqJWluJSoqIG9wZXJhdG9yLg0KDQpgYGB7cn0NCmZpbHRlcihmbGlnaHRzLCBVbmlxdWVDYXJyaWVyICVpbiUgYygiQUEiLCAiVUEiKSkNCmBgYA0KDQpTZWUsIHlvdSBkb24ndCBuZWVkIHRvIGJvdGhlciB3aXRoIHRoYXQgJCByZWZlcmVuY2UgdG8gZGF0YSBmcmFtZSBhbGwgdGhlIHRpbWUuIENvZGUgaXMgbXVjaCBuZWF0ZXIgYW5kDQpyZWFkYWJsZS4gDQoNCl9fXw0KDQojIyA0LjIgU2VsZWN0IERhdGENCg0KTGV0cyBsb29rIGF0ICoqY29sdW1uIHNlbGVjdGlvbiBkcm9wcGluZyoqIGJ5IG5hbWUuIFlvdSdsbCBiZSBkZWZpbmlldGx5IHN1cnByaXNlZCBieSB0aGUgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXRpZXMgb2YgZHBseXIuDQoNCmBgYHtyfQ0KIyBiYXNlIFIgYXBwcm9hY2ggdG8gc2VsZWN0IERlcFRpbWUsIEFyclRpbWUsIGFuZCBGbGlnaHROdW0gY29sdW1ucw0KDQpmbGlnaHRzWywgYygiRGVwVGltZSIsICJBcnJUaW1lIiwgIkZsaWdodE51bSIpXQ0KDQpgYGANCg0KYGBge3J9DQojIGRwbHlyIGFwcHJvYWNoDQoNCnNlbGVjdChmbGlnaHRzLCBEZXBUaW1lLCBBcnJUaW1lLCBGbGlnaHROdW0pDQpgYGANCg0KX19fDQoNClVzZSBjb2xvbiB0byBzZWxlY3QgbXVsdGlwbGUgY29udGludW91cyBjb2x1bW5zLCBhbmQgdXNlICoqY29udGFpbnMqKiB0byBtYXRjaCBjb2x1bW5zIGJ5IG5hbWUgbm90ZToNCiJzdGFydHNfd2l0aCIsICJlbmRzX3dpdGgiIGNhbiBhbHNvIGJlIHVzZWQgdG8gbWF0Y2ggY29sdW1ucyBieSBuYW1lDQoNCmBgYHtyfQ0Kc2VsZWN0KGZsaWdodHMsIFllYXI6RGF5b2ZNb250aCwgY29udGFpbnMoIlRheGkiKSwgY29udGFpbnMoIkRlbGF5IikpDQpgYGANCg0KX19fDQoNCk5vdywgd2hhdCBpZiB3ZSB3YW50ZWQgdG8gZG8gbWFueSBvcGVyYXRpb25zIGF0IG9uY2U7IGZvciBleGFtcGxlLCBzZWxjdGlvbiBhbmQgY29uZGl0aW9uYWwgZmlsdGVyaW5nLiBXZSBjYW4gZG8gc28gYnkgbmVzdGluZyBvdXIgZnVuY3Rpb25zLg0KDQpgYGB7cn0NCiMgbmVzdGluZyBtZXRob2QgdG8gc2VsZWN0IFVuaXF1ZUNhcnJpZXIgYW5kIERlcERlbGF5IGNvbHVtbnMgYW5kIGZpbHRlciBmb3IgZGVsYXlzIG92ZXIgNjAgbWludXRlcw0KDQpmaWx0ZXIoc2VsZWN0KGZsaWdodHMsIFVuaXF1ZUNhcnJpZXIsIERlcERlbGF5KSwgRGVwRGVsYXkgPiA2MCkNCmBgYA0KDQpUaGlzIG5lc3RpbmcgbWV0aG9kb2xvZ3kgYmVjb21lcyB2ZXJ5IGN1bWJlcnNvbWUuIFRoaXMgZGVmaWVzIHRoZSBwdXJwb3NlIHdpdGggd2hpY2ggd2Ugc3RhcnRlZCwgbWFraW5nIG91ciBjb2RlIG1vcmUgcmVhZGFibGUuIA0KDQpfX18NCg0KSGVyZSBjb21lcyB0byB5b3VyIHJlc2N1ZSAqKiU+JSoqIG9wZXJhdG9yLCBhbHNvIGNhbGxlZCAqKmNoYWluaW5nIG9wZXJhdG9yKiouIEJhc2ljYWxseSwgd2hlbiB5b3UgdXNlIHRoaXMgb3BlcmF0b3IsIGV2ZXJ5IHN1YnNlcXVlbnQgbGluZSBvZiBjb2RlIGluaGVyaXRzIGlucHV0cyBmcm9tIHRoZSBwcmV2aW91cyBsaW5lLiBZb3UnbGwgYmUgYWJsZSB0byBiZXR0ZXIgdW5kZXJzdGFuZCB0aGlzIHdpdGggdGhlIGZvbGxvd2luZyBleGFtcGxlLiBMYXRlciBvbiB3ZSdsbCByZXdyaXRlIHRoZSBhYm92ZSBuZXN0ZWQgY29kZSB3aXRoIHRoZSBjaGFpbmluZyBvcGVyYXRvci4NCg0KYGBge3J9DQp4PXNhbXBsZSgxMCw2KQ0KeCAlPiUNCmxvZygpICU+JQ0Kc3VtKCkNCmBgYA0KDQpTZWUsIHlvdSBkb24ndCBoYXZlIHRvIHBhc3MgYW55IGlucHV0IHRvIHRob3NlIGZ1bmN0aW9ucywgeCBnb2VzIGFzIGlucHV0IHRvIGxvZyBhbmQgdGhlbiBtb2RpZmllZCB4IGFzDQpsb2coeCkgZ29lcyBhcyBpbnB1dCB0byBzdW0uIA0KDQpfX18NCg0KTGV0cyBzZWUgaG93IHdlIGNhbiB1c2UgdGhpcyB0byByZXdyaXRlIHRoZSBuZXN0ZWQgZnVuY3Rpb24gdGhhdCB3ZSBzYXcgYWJvdmUuDQoNCmBgYHtyfQ0KIyBjaGFpbmluZyBtZXRob2QNCmZsaWdodHMgJT4lDQpzZWxlY3QoVW5pcXVlQ2FycmllciwgRGVwRGVsYXkpICU+JQ0KZmlsdGVyKERlcERlbGF5ID4gNjApDQpgYGANCg0KU2VlLCBubyBuZWVkIHRvIG5lc3Qgb3Iga2VlcCBvbiBnaXZpbmcgZGF0YSByZWZlcmVuY2UgZm9yIGV2ZXJ5IG9wZXJhdGlvbi4gSXNuJ3QgdGhhdCBuZWF0ISEgDQoNCl9fXw0KX19fDQoNCiMjIDQuMyBTb3J0IERhdGENCg0KTmV4dCB3ZSBtb3ZlIHRvIG9yZGVyaW5nL3NvcnRpbmcgb3VyIGRhdGEgYnkgdXNpbmcgdmVyYiBhcnJhbmdlLg0KDQpgYGB7cn0NCiMgYmFzZSBSIGFwcHJvYWNoIHRvIHNlbGVjdCBVbmlxdWVDYXJyaWVyIGFuZCBEZXBEZWxheSBjb2x1bW5zIGFuZCBzb3J0IGJ5IERlcERlbGF5DQoNCmZsaWdodHNbb3JkZXIoZmxpZ2h0cyREZXBEZWxheSksIGMoIlVuaXF1ZUNhcnJpZXIiLCAiRGVwRGVsYXkiKV0NCmBgYA0KDQpgYGB7cn0NCiMgZHBseXIgYXBwcm9hY2gNCg0KZmxpZ2h0cyAlPiUNCnNlbGVjdChVbmlxdWVDYXJyaWVyLCBEZXBEZWxheSkgJT4lDQphcnJhbmdlKERlcERlbGF5KQ0KYGBgDQoNCl9fXw0KX19fDQoNCiMjIDQuNCBNb2RpZnkgRGF0YQ0KDQpOZXh0IHN0ZXAgaXMgdG8gKiptdXRhdGUqKiBvciBtb2RpZnlpbmcvYWRkaW5nIGRhdGEgdG8gZXhpc3RpbmcgZGF0YS4NCg0KYGBge3J9DQojIGJhc2UgUiBhcHByb2FjaCB0byBjcmVhdGUgYSBuZXcgdmFyaWFibGUgU3BlZWQgKGluIG1waCkNCg0KZmxpZ2h0cyRTcGVlZCA8LSBmbGlnaHRzJERpc3RhbmNlIC8gZmxpZ2h0cyRBaXJUaW1lKjYwDQpmbGlnaHRzWywgYygiRGlzdGFuY2UiLCAiQWlyVGltZSIsICJTcGVlZCIpXQ0KYGBgDQoNCmBgYHtyfQ0KIyBkcGx5ciBhcHByb2FjaA0KDQpmbGlnaHRzICU+JQ0Kc2VsZWN0KERpc3RhbmNlLCBBaXJUaW1lKSAlPiUNCm11dGF0ZShTcGVlZCA9IERpc3RhbmNlL0FpclRpbWUqNjApDQpgYGANCg0KX19fDQoNCldoYXQgd2UgaGF2ZSBiZWVuIGRvaW5nIGlzIGdldHRpbmcgdGhlIG91dHB1dCB0byBkaXNwbGF5LCBpZiB5b3Ugd2FudGVkIHRvIHNhdmUgaXQgY291bGQgZG8gYXMgd2UgdXN1YWxseSBkbyBpbiBSLiBTYXksIHdlIHdhbnRlZCB0byBzYXZlIGFib3ZlIG91dHB1dCB0byBzb21lIGRhdGEgZnJhbWUuDQoNCmBgYHtyfQ0KZmxpZ2h0X3N1Yj1mbGlnaHRzICU+JQ0Kc2VsZWN0KERpc3RhbmNlLCBBaXJUaW1lKSAlPiUNCm11dGF0ZShTcGVlZCA9IERpc3RhbmNlL0FpclRpbWUqNjApDQpgYGANCg0KX19fDQpfX18NCg0KIyMgNC41IFN1bW1hcml6aW5nIERhdGENCg0KV2UgYXJlIGRvbmUgd2l0aCBkYXRhIHdyYW5nbGluZyB3aXRob3V0IGNvbGxhcHNpbmcgaXQuIE5leHQgd2UgbG9vayBhdCBleGFjdGx5IHRoYXQsICoqc3VtbWFyaXNpbmcgZGF0YSoqIGJ5IGdyb3VwcyBvciBjb2xsYXBzaW5nIGRhdGEgdG8gaXRzIGdyb3VwIHdpc2Ugc3VtbWFyaWVzIHVzaW5nIGRwbHlyLg0KDQpgYGB7cn0NCiMgZHBseXIgYXBwcm9hY2g6IGNyZWF0ZSBhIHRhYmxlIGdyb3VwZWQgYnkgRGVzdCwgYW5kIHRoZW4gc3VtbWFyaXNlIGVhY2ggZ3JvdXAgYnkgdGFraW5nIHRoZSBtZWFuIG9mIEFyckRlbGF5DQoNCmZsaWdodHMgJT4lDQpncm91cF9ieShEZXN0KSAlPiUNCnN1bW1hcmlzZShhdmdfZGVsYXkgPSBtZWFuKEFyckRlbGF5LCBuYS5ybT1UUlVFKSkNCmBgYA0KDQpfX18NCg0KVGhpcyBwcmV0dHkgbXVjaCBmaW5pc2hlcyBvdXIgZGlzY3Vzc2lvbiBvbiBkcGx5ciB2ZXJicyBhbmQgYWR2ZXJicy4gV2UgaGF2ZSBnaXZlbiBmZXcgbW9yZSBleGFtcGxlcyB0bw0KbGVhcm4gbmV3IHVzZWZ1bCBmdW5jdGlvbmFsaXRpZXMgd2hpY2ggd2UgaGF2ZW50IGJlZW4gaW50cm9kdWNlZCB5ZXQuDQoNCkZvciBlYWNoIGRheSBvZiB0aGUgeWVhciwgY291bnQgdGhlIHRvdGFsIG51bWJlciBvZiBmbGlnaHRzIGFuZCBzb3J0IGluIGRlc2NlbmRpbmcgb3JkZXINCg0KYGBge3J9DQp6PWZsaWdodHMgJT4lDQpncm91cF9ieShNb250aCwgRGF5b2ZNb250aCkgJT4lDQpzdW1tYXJpc2UoZmxpZ2h0X2NvdW50ID0gbigpKSAlPiUNCmFycmFuZ2UoZGVzYyhmbGlnaHRfY291bnQpKQ0KYGBgDQoNCl9fXw0KDQpMZXRzIHJld3JpdGUgbW9yZSBzaW1wbHkgd2l0aCB0aGUgKip0YWxseSoqIGZ1bmN0aW9uDQoNCmBgYHtyfQ0KZmxpZ2h0cyAlPiUNCmdyb3VwX2J5KE1vbnRoLCBEYXlvZk1vbnRoKSAlPiUNCnRhbGx5KHNvcnQgPSBUUlVFKQ0KYGBgDQoNCl9fXw0KDQpGb3IgZWFjaCBkZXN0aW5hdGlvbiwgY291bnQgdGhlIHRvdGFsIG51bWJlciBvZiBmbGlnaHRzIGFuZCB0aGUgbnVtYmVyIG9mIGRpc3RpbmN0IHBsYW5lcyB0aGF0IGZsZXcgdGhlcmUuDQoNCmBgYHtyfQ0KZmxpZ2h0cyAlPiUNCmdyb3VwX2J5KERlc3QpICU+JQ0Kc3VtbWFyaXNlKGZsaWdodF9jb3VudCA9IG4oKSwgcGxhbmVfY291bnQgPSBuX2Rpc3RpbmN0KFRhaWxOdW0pKQ0KYGBgDQoNCl9fXw0KDQpGb3IgZWFjaCBkZXN0aW5hdGlvbiwgc2hvdyB0aGUgbnVtYmVyIG9mIGNhbmNlbGxlZCBhbmQgbm90IGNhbmNlbGxlZCBmbGlnaHRzLg0KDQpgYGB7cn0NCmZsaWdodHMgJT4lDQpncm91cF9ieShEZXN0KSAlPiUNCnNlbGVjdChDYW5jZWxsZWQpICU+JQ0KdGFibGUoKSAlPiUNCmhlYWQoKQ0KYGBgDQoNCl9fXw0KDQpGb3IgZWFjaCBtb250aCwgY2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgZmxpZ2h0cyBhbmQgdGhlIGNoYW5nZSBmcm9tIHRoZSBwcmV2aW91cyBtb250aC4NCg0KYGBge3J9DQpmbGlnaHRzICU+JQ0KZ3JvdXBfYnkoTW9udGgpICU+JQ0Kc3VtbWFyaXNlKGZsaWdodF9jb3VudCA9IG4oKSkgJT4lDQptdXRhdGUoY2hhbmdlID0gZmxpZ2h0X2NvdW50IC0gbGFnKGZsaWdodF9jb3VudCkpDQpgYGANCg0KX19fDQoNCkFnYWluLCBsZXRzIHJld3JpdGUgbW9yZSBzaW1wbHkgd2l0aCB0aGUgKip0YWxseSoqIGZ1bmN0aW9uLg0KDQpgYGB7cn0NCg0KDQpmbGlnaHRzICU+JQ0KZ3JvdXBfYnkoTW9udGgpICU+JQ0KdGFsbHkoKSAlPiUNCm11dGF0ZShjaGFuZ2UgPSBuIC0gbGFnKG4pKQ0KYGBgDQoNCl9fXw0KDQpCYXNlIFIgYXBwcm9hY2ggdG8gdmlldyB0aGUgc3RydWN0dXJlIG9mIGFuIG9iamVjdA0KDQpgYGB7cn0NCnN0cihmbGlnaHRzKQ0KYGBgDQoNCl9fXw0KDQpkcGx5ciBhcHByb2FjaDogYmV0dGVyIGZvcm1hdHRpbmcsIGFuZCBhZGFwdHMgdG8geW91ciBzY3JlZW4gd2lkdGguDQoNCmBgYHtyfQ0KZ2xpbXBzZShmbGlnaHRzKQ0KYGBgDQoNCl9fXw0KX19fDQoNCiMgNS4gU2FtcGxpbmcgRGF0YQ0KDQpBcyBtb3Zpbmcgc2xvd2x5IHRvd2FyZHMgcHJlZGljdGl2ZSBtb2RlbGxpbmcsIHlvdSdkIG5lZWQgdG8gdGFrZSByYW5kb21lIHNhbXBsZSBmcm9tIHlvdXIgZGF0YSBmb3INCmRpZmZlcmVudCBwdXJwb3Nlcy4gWW91IGNhbiBhY2hpZXZlIHRoYXQgaW4gYSByYXRoZXIgc2ltcGxlIG1hbm5lciBieSB1c2luZyB0aGUgZnVuY3Rpb24gc2FtcGxlIHdoaWNoIHdlDQpoYXZlIHVzZWQgYSBsb3Qgc28gZmFyLiBIZXJlIGdvZXMgYW4gZXhhbXBsZSBmb3IgdGFraW5nIDcwJSByYW5kb20gZGF0YSBmcm9tIGRhdGEgZnJhbWUgbXRjYXJzLg0KDQpgYGB7cn0NCiMgd2UgYXJlIHVzaW5nIHNldC5zZWVkIGZvciBvdXIgcmFuZG9tIHNhbXBsZSB0byBiZSByZXByb2R1Y2libGUNCg0Kc2V0LnNlZWQoMSkNCnM9c2FtcGxlKDE6bnJvdyhtdGNhcnMpLDAuNypucm93KG10Y2FycykpDQpgYGANCg0KX19fDQoNCllvdSBjYW4gbm93IHVzZSB0aGlzIHZlY3RvciAqKnMqKiBhcyByb3cgaW5kZXggdmVjdG9yIHRvIHRha2Ugc2FtcGxlIGRhdGEgZnJvbSB0aGUgZGF0YSBmcmFtZS4NCg0KYGBge3J9DQptdGNhcnNfc2FtcGxlPW10Y2Fyc1tzLF0NCmBgYA0KDQpfX18NCg0KSG93IGRvIEkgZ2V0IHRoZSByZXN0IG9mIHRoZSBvYnNlcnZhdGlvbnMgd2hpY2ggYXJlIG5vdCBpbiBzYW1wbGUgdGFrZW4gYWJvdmU/DQoNCmBgYHtyfQ0KbXRjYXJzX3JlbWFpbmluZz1tdGNhcnNbLXMsXQ0KYGBgDQoNCl9fXw0KDQpIb3cgdG8gcmFuZG9tbHkgYm9vdHN0cmFwIHlvdXIgZGF0YT8gQWdhaW4sIHlvdSBjYW4gYWNoaWV2ZSB0aGF0IGJ5IHVzaW5nIHNhbXBsaW5nIHdpdGggcmVwbGFjZW1lbnQNCndpdGggZnVuY3Rpb24gc2FtcGxlDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMSkNCnM9c2FtcGxlKDE6bnJvdyhtdGNhcnMpLDEwMCxyZXBsYWNlID0gVFJVRSkNCm10Y2Fyc19ib290c3RyYXBwZWQ9bXRjYXJzW3MsXQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQo=